package com.stephenone.zhdaily.data.source.local;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.gson.Gson;
import com.squareup.sqlbrite2.BriteDatabase;
import com.squareup.sqlbrite2.SqlBrite;
import com.stephenone.zhdaily.data.bean.News;
import com.stephenone.zhdaily.data.source.NewsDataSource;
import com.stephenone.zhdaily.uitl.schedulers.BaseSchedulerProvider;


import java.util.List;

import javax.annotation.Nonnull;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Created by Administrator on 2018/3/5.
 */

public class NewsLocalDataSource implements NewsDataSource {
    public static final String PRARM_LASTEST = "latest";
    private static final String TAG = NewsLocalDataSource.class.getSimpleName();

    @Nullable
    private static NewsLocalDataSource INSTANCE;

    @NonNull
    private final BriteDatabase mDatabaseHelper;

    @NonNull
    private Function<Cursor,News> mNewsMapperFunction;

    private Gson mGson;

    private NewsLocalDataSource(
            @NonNull Context context,
            @NonNull BaseSchedulerProvider schedulerProvider){
        checkNotNull(context, "context cannot be null");
        checkNotNull(schedulerProvider, "scheduleProvider cannot be null");
        mGson = new Gson();
        SqlBrite sqlBrite = new SqlBrite.Builder().build();
        SQLiteOpenHelper dbHelper = new NewsDbHelper(context);
        mDatabaseHelper = sqlBrite.wrapDatabaseHelper(dbHelper, schedulerProvider.io());
        // TODO: 2018/3/8
        mDatabaseHelper.setLoggingEnabled(true);
        mNewsMapperFunction = this::getOneNews;
    }

    private News getOneNews(Cursor c){
        String json = c.getString(c.getColumnIndexOrThrow(NewsPersistenceContract.NewsEntry.COLUMN_NAME_JSON));
        return mGson.fromJson(json,News.class);
    }

    public static NewsLocalDataSource getInstance(
            @NonNull Context context,
            @NonNull BaseSchedulerProvider schedulerProvider){
        if(INSTANCE == null){
            INSTANCE = new NewsLocalDataSource(context,schedulerProvider);
        }
        return INSTANCE;
    }

    public static void destroyInstance(){
        INSTANCE = null;
    }

    @Override
    public Flowable<List<News>> getNews() {
        return null;
    }

    @Override
    public Flowable<Optional<News>> getLatestNews() {
        String[] projection = {
                NewsPersistenceContract.NewsEntry.COLUMN_NAME_DATE,
                NewsPersistenceContract.NewsEntry.COLUMN_NAME_JSON
        };
        String sql = String.format("SELECT %s FROM %s WHERE %s LIKE ?",
                TextUtils.join(",",projection), NewsPersistenceContract.NewsEntry.TABLE_NAME,NewsPersistenceContract.NewsEntry.COLUMN_NAME_DATE);
        return mDatabaseHelper.createQuery(NewsPersistenceContract.NewsEntry.TABLE_NAME,sql,PRARM_LASTEST)
                .mapToOne(cursor -> Optional.of(mNewsMapperFunction.apply(cursor)))
//                .mapToOneOrDefault(cursor -> Optional.of(mNewsMapperFunction.apply(cursor)),Optional.<News>absent())
                .toFlowable(BackpressureStrategy.BUFFER);
    }

    @Override
    public Flowable<Optional<News>> getOneNews(@NonNull String date) {
        String[] projection = {
                NewsPersistenceContract.NewsEntry.COLUMN_NAME_DATE,
                NewsPersistenceContract.NewsEntry.COLUMN_NAME_JSON
        };
        String sql = String.format("SELECT %s FROM %s WHERE %s LIKE ?",
                TextUtils.join(",",projection), NewsPersistenceContract.NewsEntry.TABLE_NAME,NewsPersistenceContract.NewsEntry.COLUMN_NAME_DATE);
        Log.e(TAG, "getOneNews: " + sql );
        return mDatabaseHelper.createQuery(NewsPersistenceContract.NewsEntry.TABLE_NAME,sql,date)
//                .mapToOne(cursor -> Optional.of(mNewsMapperFunction.apply(cursor)))
//                .mapToOne(new io.reactivex.functions.Function<Cursor, Optional<News>>() {
//                    @Override
//                    public Optional<News> apply(Cursor cursor) throws Exception {
//                        Log.e(TAG, "apply: "  );
//                        return Optional.of(mNewsMapperFunction.apply(cursor));
//                    }
//                })
                .mapToOneOrDefault(cursor -> Optional.of(mNewsMapperFunction.apply(cursor)),Optional.<News>absent())
                .toFlowable(BackpressureStrategy.BUFFER);
    }

    @Override
    public void refreshNews() {

    }

    @Override
    public void saveNews(@NonNull String date,@Nonnull News news) {
        checkNotNull(news);
        ContentValues values = new ContentValues();
        values.put(NewsPersistenceContract.NewsEntry.COLUMN_NAME_DATE,date);
        values.put(NewsPersistenceContract.NewsEntry.COLUMN_NAME_JSON,mGson.toJson(news));
        mDatabaseHelper.insert(NewsPersistenceContract.NewsEntry.TABLE_NAME,values, SQLiteDatabase.CONFLICT_REPLACE);
    }


}
